package com.bw.http.http.okhttp

import android.annotation.SuppressLint
import android.os.Environment
import com.alibaba.android.arouter.launcher.ARouter
import com.blankj.utilcode.util.CacheDoubleStaticUtils.put
import com.bw.base.conts.BaseConst
import com.bw.base.path.RouterPath
import com.bw.http.BuildConfig
import com.tencent.mmkv.MMKV
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.lang.reflect.Proxy
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLHandshakeException
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager

/**
 * 使用okhttp和Retrofit封装
 */
object OKHttpClientManger {

    /**
     * 获取普通客户端.
     * 支持Http
     */
    fun createOkHttpClient(): OkHttpClient {
        val okBuilder = OkHttpClient.Builder()//建造者设计模式
        okBuilder.apply {
            //写入超时
            writeTimeout(10, TimeUnit.SECONDS)
            //读取超时
            readTimeout(10,TimeUnit.SECONDS)
            //连接超时
            connectTimeout(10,TimeUnit.SECONDS)
            //日志拦截器（避免线上的环境给系统输出日志）
            if (BuildConfig.DEBUG){//BuildConfig文件是在构建的时候生成的，在app里面是存在的，在lib里面是不存在的
                addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            }
            //Header头拦截器
            addInterceptor(getHeaderInterceptor())


        }
        return okBuilder.build()
    }

    /**
     * 获取一个OKHttpClient对象
     */

    @SuppressLint("SuspiciousIndentation")
    private fun getOkHttpClient(): OkHttpClient {
        val okBuilder = OkHttpClient.Builder()//建造者设计模式
            okBuilder.apply {
                //写入超时
                writeTimeout(10, TimeUnit.SECONDS)
                //读取超时
                readTimeout(10,TimeUnit.SECONDS)
                //连接超时
                connectTimeout(10,TimeUnit.SECONDS)
                //日志拦截器（避免线上的环境给系统输出日志）
                if (BuildConfig.DEBUG){//BuildConfig文件是在构建的时候生成的，在app里面是存在的，在lib里面是不存在的
                    addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                }
                //Header头拦截器
                addInterceptor(getHeaderInterceptor())

                //服务器异常拦截器
                addInterceptor(getServerInterceptor())

                //如果要支持Https请求，支持加密传输（对称和非对称加密都可以）
                sslSocketFactory(sslSocketFactory, trustManager)

                //防止使用网络代理，抓包接口
                proxy(java.net.Proxy.NO_PROXY)
                //设置Http网络协议版本  Http1.0,Http2.0 和Http3.0(QUIC)
                protocols(listOf(Protocol.HTTP_2))

                //设置网络缓存（默认没有网络缓存）
                val externalDirPath = Environment.getExternalStorageDirectory().absolutePath
                if (externalDirPath.isEmpty()){
                    cache(Cache(File("${externalDirPath}/smartParkCache"),10*1024*1024))//10M
                }
            }
        return okBuilder.build()
    }


    //定义SSL
    private val sslSocketFactory:SSLSocketFactory
        get() = try {
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, arrayOf(), SecureRandom())
            sslContext.socketFactory
        }catch (e:Exception){
            throw RuntimeException(e.message)
        }


    private val trustManager:X509TrustManager
        get() = object :X509TrustManager{
            /**
             * 校验客户端证书
             */
            override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {

            }
            /**
             * 校验服务端证书
             */
            override fun checkServerTrusted(chain: Array<out X509Certificate>?, p1: String?) {
                //防止抓包  如：fiddler Charless 抓包工具
                chain?.forEach {
                    if (it.issuerX500Principal.name.contains("Charles") ||
                            it.issuerX500Principal.name.contains("Fiddler")){
                        throw SSLHandshakeException("当前应用不允许抓包！请关闭抓包工具！")
                    }
                }
            }
            /**
             * 获取可以被接收端
             */
            override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()

        }



    /**
     * 请求头 拦截器
     * 设计模式：责任链模式
     */
    private fun getHeaderInterceptor(): Interceptor {

        return object :Interceptor{
            override fun intercept(chain: Interceptor.Chain): Response {
                val token = MMKV.defaultMMKV().decodeString("token","eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxOTIzMzE2MzM4NCJ9.M8_GNczI9HXSmPw6ln1cPqs62TqXcECDIn3lufVO5mg").toString()
                //从请求链上获取请求建造者对象
                var newRequestBuilder = chain.request().newBuilder()
                newRequestBuilder.header("token",token)

                //获取AccessId
                val accessId = MMKV.defaultMMKV().decodeString("accessId",BaseConst.APP_ACCESS_ID).toString()
                newRequestBuilder.header("accessId",accessId)

                //生成新的请求对象
                var newRequest = newRequestBuilder.build()

                //执行请求获取返回接口
                var response = chain.proceed(newRequest)

                //校验一下Token是否过期
                if (response.code == 401 || response.code == 403){
                    ARouter.getInstance().build(RouterPath.PATH_LOGIN_PAGE).navigation()
                }
                return response
            }

        }

    }


    /**
     * 服务器返回拦截器
     */

    private fun getServerInterceptor(): Interceptor {
        return object :Interceptor{
            override fun intercept(chain: Interceptor.Chain): Response {
                //执行请求获取返回
                var response = chain.proceed(chain.request())
                var responseBuilder = response.newBuilder()

                //代表服务器接口报错
                if (response.code == 500){
                    var  errorJson = JSONObject().let {
                        put("code",500)
                        put("message","服务器异常，请联系客服！")
                    }

                    responseBuilder.body(errorJson.toString().toResponseBody("application/json;charset=UTF-8".toMediaTypeOrNull()))
                }

                return responseBuilder.build()
            }

        }
    }


}







////////////////////////////////////////
